//
//  TransformViewController.m
//  LayerProperty
//
//  Created by hao on 2018/4/2.
//  Copyright © 2018年 hao. All rights reserved.
//

#import "TransformViewController.h"
#import <GLKit/GLKit.h>
#import "Header.h"

#define LIGHT_DIRECTION 0, 1, -0.5
#define AMBIENT_LIGHT 0.5

@interface TransformViewController ()

@property (nonatomic, weak) UIImageView *transformIV;

@property (nonatomic, weak) UIView *containerView;

@end

@implementation TransformViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = UIColorWithRGB(190, 190, 190);
//    [self viewAffineTransform];
//    [self transform3D_1];
    [self transform3D_2];
}

/** 为立方体做一个动态的光亮和阴影 */
- (void)applyLightingToFace:(CALayer *)face
{
    //add lighting layer
    CALayer *layer = [CALayer layer];
    layer.frame = face.bounds;
    [face addSublayer:layer];
    //convert the face transform to matrix
    //(GLKMatrix4 has the same structure as CATransform3D)
    //译者注：GLKMatrix4和CATransform3D内存结构一致，但坐标类型有长度区别，所以理论上应该做一次float到CGFloat的转换，感谢[@zihuyishi](https://github.com/zihuyishi)同学~
    CATransform3D transform = face.transform;
    GLKMatrix4 matrix4 = *(GLKMatrix4 *)&transform;
    GLKMatrix3 matrix3 = GLKMatrix4GetMatrix3(matrix4);
    //get face normal
    GLKVector3 normal = GLKVector3Make(0, 0, 1);
    normal = GLKMatrix3MultiplyVector3(matrix3, normal);
    normal = GLKVector3Normalize(normal);
    //get dot product with light direction
    GLKVector3 light = GLKVector3Normalize(GLKVector3Make(LIGHT_DIRECTION));
    float dotProduct = GLKVector3DotProduct(light, normal);
    //set lighting layer opacity
    CGFloat shadow = 1 + dotProduct - AMBIENT_LIGHT;
    NSLog(@"shadow = %.2f", shadow);
    UIColor *color = [UIColor colorWithWhite:0 alpha:shadow];
    layer.backgroundColor = color.CGColor;
}

/** 创建一个立方体 */
- (void)transform3D_2
{
    NSArray<UIButton *> *btnFaceArr = [self createBtnArr];
    //set up the container sublayer transform
    CATransform3D perspective = CATransform3DIdentity;
    perspective.m34 = -1.0 / 500.0;
    perspective = CATransform3DRotate(perspective, -M_PI_4, 1, 0, 0);
    perspective = CATransform3DRotate(perspective, -M_PI_4, 0, 1, 0);
    self.containerView.layer.sublayerTransform = perspective;
    // translation的值为控件宽度的一半 (控件宽高一致)
    CGFloat translation = 75;
    //add cube face 1
    CATransform3D transform = CATransform3DMakeTranslation(0, 0, translation);
    [self addFace:btnFaceArr.firstObject withTransform:transform];
    //add cube face 2
    transform = CATransform3DMakeTranslation(translation, 0, 0);
    transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
    [self addFace:btnFaceArr[1] withTransform:transform];
    //add cube face 3
    transform = CATransform3DMakeTranslation(0, -translation, 0);
    transform = CATransform3DRotate(transform, M_PI_2, 1, 0, 0);
    [self addFace:btnFaceArr[2] withTransform:transform];
    //add cube face 4
    transform = CATransform3DMakeTranslation(0, translation, 0);
    transform = CATransform3DRotate(transform, -M_PI_2, 1, 0, 0);
    [self addFace:btnFaceArr[3] withTransform:transform];
    //add cube face 5
    transform = CATransform3DMakeTranslation(-translation, 0, 0);
    transform = CATransform3DRotate(transform, -M_PI_2, 0, 1, 0);
    [self addFace:btnFaceArr[4] withTransform:transform];
    //add cube face 6
    transform = CATransform3DMakeTranslation(0, 0, -translation);
    transform = CATransform3DRotate(transform, M_PI, 0, 1, 0);
    [self addFace:btnFaceArr[5] withTransform:transform];
}

/** 设置控件的旋转角度，阴影和光亮 */
- (void)addFace:(UIButton *)face withTransform:(CATransform3D)transform
{
    //get the face view and add it to the container
    //    UIView *face = self.faces[index];
    [self.containerView addSubview:face];
    //center the face view within the container
    CGSize containerSize = self.view.bounds.size;
    face.center = CGPointMake(containerSize.width / 2.0, containerSize.height / 2.0);
    // apply the transform
    face.layer.transform = transform;
    //apply lighting
    [self applyLightingToFace:face.layer];
}

/** 透视投影
    矩阵 m34的默认值是0，设置m34为 -1.0/d 透视投影效果，d代表了想象中视角相机和屏幕之间的距离，以像素为单位，那应该如何计算这个距离呢？实际上并不需要，大概估算一个就好了。
    因为视角相机实际上并不存在，所以可以根据屏幕上的显示效果自由决定它的防止的位置。通常500-1000就已经很好了，减少距离的值会增强透视效果，所以一个非常微小的值会让它看起来更加失真，然而一个非常大的值会让它基本失去透视效果，所以视情况而定 */
- (void)transform3D_1
{
    // CALayer.doubleSided 属性控制图层的背面是否要被绘制。这是一个BOOL类型，默认为YES，如果设置为NO，那么当图层正面从相机视角消失的时候，它将不会被绘制。
    [UIView animateWithDuration:1 animations:^{
        CATransform3D transform3D = CATransform3DIdentity;
        transform3D.m34 = -1.0/500.0;
        // 旋转 M_PI 将图片翻转展示背面，镜像图片
        // 曾经听过一个需求，手机将OBD读取的数据镜像显示，正放于汽车挡风玻璃下方，屏幕信息投影到玻璃上正面展示，可以考虑这种镜像方式实现
        transform3D = CATransform3DRotate(transform3D, M_PI, 0, 1, 0);
        self.transformIV.layer.transform = transform3D;
    }];
}

/** 控件的二维仿射变换 */
- (void)viewAffineTransform
{
    // 如果需要混合两个已经存在的变换矩阵，就可以使用如下方法，在两个变换的基础上创建一个新的变换
    // CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);
    [UIView animateWithDuration:1 animations:^{
        CGAffineTransform transform = CGAffineTransformIdentity;
        // 缩放
        transform = CGAffineTransformScale(transform, 1.5, 1.5);
        // 旋转
        transform = CGAffineTransformRotate(transform, M_PI_4);
        // 移动
        transform = CGAffineTransformTranslate(transform, 50, 0);
        self.transformIV.transform = transform;
        // layer.affineTransform 等价于 view.transform
//        self.transformIV.layer.affineTransform;
    }];
}

- (UIImageView *)transformIV
{
    if (!_transformIV) {
        UIImage *image = [UIImage imageNamed:@"icon"];
        UIImageView *iv = [[UIImageView alloc] initWithImage:image];
        iv.frame = CGRectMake(0, 0, image.size.width, image.size.height);
        iv.center = CGPointMake(ScreenWidth*0.5, ScreenHeight*0.5);
        [self.view addSubview:iv];
        _transformIV = iv;
    }
    return _transformIV;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    
}

- (NSArray<UIButton *> *)createBtnArr
{
    NSMutableArray *arr = [NSMutableArray arrayWithCapacity:6];
    if (!self.containerView) {
        UIView *v = [[UIView alloc] init];
        [self.view addSubview:v];
        v.frame = self.view.bounds;
        self.containerView = v;
    }
    for (int i = 1; i <= 6; i++) {
        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
        [btn setTitle:[NSString stringWithFormat:@"%d", i] forState:UIControlStateNormal];
        [btn setTitleColor:RandomColor forState:UIControlStateNormal];
//        [self.containerView addSubview:btn];
        btn.frame = CGRectMake(0, 0, 150, 150);
        btn.backgroundColor = [UIColor whiteColor];
        btn.tag = i;
        btn.layer.borderWidth = 1.f;
        btn.layer.borderColor = [UIColor blueColor].CGColor;
        btn.titleLabel.font = [UIFont systemFontOfSize:24];
        [btn addTarget:self action:@selector(cubeClick:) forControlEvents:UIControlEventTouchUpInside];
        [arr addObject:btn];
    }
    return arr.mutableCopy;
}

/** 点击事件的处理由视图在父视图中的顺序决定的，并不是3D空间中的Z轴顺序。当给立方体添加视图的时候，我们实际上是按照   一个顺序添加，所以按照视图/图层顺序来说，4，5，6在3的前面
   doubleSided设置成NO可以解决这个问题，因为它不再渲染视图后面的内容，但实际上并不起作用。因为背对相机而隐藏的视图仍然会响应点击事件（这和通过设置hidden属性或者设置alpha为0而隐藏的视图不同，那两种方式将不会响应事件）。所以即使禁止了双面渲染仍然不能解决这个问题（虽然由于性能问题，还是需要把它设置成NO）
   这里有几种正确的方案：把除了表面3的其他视图userInteractionEnabled属性都设置成NO来禁止事件传递。或者简单通过代码把视图3覆盖在视图6上
 */
- (void)cubeClick:(UIButton *)btn
{
    NSLog(@"btn.tag = %zd", btn.tag);
}

@end
